// author: Nicolas Liu
// description: 64x64 booth encoder and partial product compressor

`include "PRV564Config.v"
`include "PRV564Define.v"

module mul(
    input wire[63:0] rs1,
    input wire[63:0] rs2,
    input wire sign1,
    input wire sign2,
    output wire[127:0] x,
    output wire[127:0] y
);

    wire[64:0] rs1_ext;
    wire[66:0] rs2_ext;
    wire[127:0] pp[0:33];
    wire[65:0] carry;
    wire[127:0] s_l1_1, s_l1_2, s_l1_3, s_l1_4, s_l1_5, s_l1_6, s_l1_7, s_l1_8, s_l1_9, s_l1_10, s_l1_11;
    wire[127:0] c_l1_1, c_l1_2, c_l1_3, c_l1_4, c_l1_5, c_l1_6, c_l1_7, c_l1_8, c_l1_9, c_l1_10, c_l1_11;
    wire[127:0] s_l2_1, s_l2_2, s_l2_3, s_l2_4, s_l2_5, s_l2_6, s_l2_7;
    wire[127:0] c_l2_1, c_l2_2, c_l2_3, c_l2_4, c_l2_5, c_l2_6, c_l2_7;
    wire[127:0] s_l3_1, s_l3_2, s_l3_3, s_l3_4, s_l3_5, c_l3_1, c_l3_2, c_l3_3, c_l3_4, c_l3_5;
    wire[127:0] s_l4_1, s_l4_2, s_l4_3, c_l4_1, c_l4_2, c_l4_3, s_l5_1, s_l5_2, c_l5_1, c_l5_2;
    wire[127:0] s_l6_1, s_l6_2, c_l6_1, c_l6_2, s_l7, c_l7, s_l8, c_l8;

    assign rs1_ext = sign1 ? {rs1[63], rs1[63:0]} : {1'b0, rs1[63:0]};
    assign rs2_ext = sign2 ? {{2{rs2[63]}}, rs2[63:0], 1'b0} : {2'b00, rs2[63:0], 1'b0};

    // generate partial products
    genvar i;
    generate
        for (i=0; i<=32; i=i+1)
        begin: haha
            booth2 u_booth(
                .x  (rs1_ext), 
                .y  (rs2_ext[2*i+2:2*i]), 
                .z  (pp[i]), 
                .c  (carry[2*i+1:2*i])
            );
        end
    endgenerate
    assign pp[33] = {62'b0, carry[65:0]};

    // compress partial products
    csa u_csa_l1_1(.x(pp[0]), .y({pp[1][125:0], 2'b0}), .z({pp[2][123:0], 4'b0}), .s(s_l1_1), .c(c_l1_1));
    csa u_csa_l1_2(.x({pp[3][121:0], 6'b0}), .y({pp[4][119:0], 8'b0}), .z({pp[5][117:0], 10'b0}), .s(s_l1_2), .c(c_l1_2));
    csa u_csa_l1_3(.x({pp[6][115:0], 12'b0}), .y({pp[7][113:0], 14'b0}), .z({pp[8][111:0], 16'b0}), .s(s_l1_3), .c(c_l1_3));
    csa u_csa_l1_4(.x({pp[9][109:0], 18'b0}), .y({pp[10][107:0], 20'b0}), .z({pp[11][105:0], 22'b0}), .s(s_l1_4), .c(c_l1_4));
    csa u_csa_l1_5(.x({pp[12][103:0], 24'b0}), .y({pp[13][101:0], 26'b0}), .z({pp[14][99:0], 28'b0}), .s(s_l1_5), .c(c_l1_5));
    csa u_csa_l1_6(.x({pp[15][97:0], 30'b0}), .y({pp[16][95:0], 32'b0}), .z({pp[17][93:0], 34'b0}), .s(s_l1_6), .c(c_l1_6));
    csa u_csa_l1_7(.x({pp[18][91:0], 36'b0}), .y({pp[19][89:0], 38'b0}), .z({pp[20][87:0], 40'b0}), .s(s_l1_7), .c(c_l1_7));
    csa u_csa_l1_8(.x({pp[21][85:0], 42'b0}), .y({pp[22][83:0], 44'b0}), .z({pp[23][81:0], 46'b0}), .s(s_l1_8), .c(c_l1_8));
    csa u_csa_l1_9(.x({pp[24][79:0], 48'b0}), .y({pp[25][77:0], 50'b0}), .z({pp[26][75:0], 52'b0}), .s(s_l1_9), .c(c_l1_9));
    csa u_csa_l1_10(.x({pp[27][73:0], 54'b0}), .y({pp[28][71:0], 56'b0}), .z({pp[29][69:0], 58'b0}), .s(s_l1_10), .c(c_l1_10));
    csa u_csa_l1_11(.x({pp[30][67:0], 60'b0}), .y({pp[31][65:0], 62'b0}), .z({pp[32][63:0], 64'b0}), .s(s_l1_11), .c(c_l1_11));
    csa u_csa_l2_1(.x(pp[33]), .y(s_l1_1), .z(s_l1_2), .s(s_l2_1), .c(c_l2_1));
    csa u_csa_l2_2(.x(s_l1_3), .y(s_l1_4), .z(s_l1_5), .s(s_l2_2), .c(c_l2_2));
    csa u_csa_l2_3(.x(s_l1_6), .y(s_l1_7), .z(s_l1_8), .s(s_l2_3), .c(c_l2_3));
    csa u_csa_l2_4(.x(s_l1_9), .y(s_l1_10), .z(s_l1_11), .s(s_l2_4), .c(c_l2_4));
    csa u_csa_l2_5(.x({c_l1_1[126:0], 1'b0}), .y({c_l1_2[126:0], 1'b0}), .z({c_l1_3[126:0], 1'b0}), .s(s_l2_5), .c(c_l2_5));
    csa u_csa_l2_6(.x({c_l1_4[126:0], 1'b0}), .y({c_l1_5[126:0], 1'b0}), .z({c_l1_6[126:0], 1'b0}), .s(s_l2_6), .c(c_l2_6));
    csa u_csa_l2_7(.x({c_l1_7[126:0], 1'b0}), .y({c_l1_8[126:0], 1'b0}), .z({c_l1_9[126:0], 1'b0}), .s(s_l2_7), .c(c_l2_7));
    csa u_csa_l3_1(.x({c_l1_10[126:0], 1'b0}), .y({c_l1_11[126:0], 1'b0}), .z(s_l2_1), .s(s_l3_1), .c(c_l3_1));
    csa u_csa_l3_2(.x(s_l2_2), .y(s_l2_3), .z(s_l2_4), .s(s_l3_2), .c(c_l3_2));
    csa u_csa_l3_3(.x(s_l2_5), .y(s_l2_6), .z(s_l2_7), .s(s_l3_3), .c(c_l3_3));
    csa u_csa_l3_4(.x({c_l2_1[126:0], 1'b0}), .y({c_l2_2[126:0], 1'b0}), .z({c_l2_3[126:0], 1'b0}), .s(s_l3_4), .c(c_l3_4));
    csa u_csa_l3_5(.x({c_l2_4[126:0], 1'b0}), .y({c_l2_5[126:0], 1'b0}), .z({c_l2_6[126:0], 1'b0}), .s(s_l3_5), .c(c_l3_5));
    csa u_csa_l4_1(.x({c_l2_7[126:0], 1'b0}), .y(s_l3_1), .z(s_l3_2), .s(s_l4_1), .c(c_l4_1));
    csa u_csa_l4_2(.x(s_l3_3), .y(s_l3_4), .z(s_l3_5), .s(s_l4_2), .c(c_l4_2));
    csa u_csa_l4_3(.x({c_l3_1[126:0], 1'b0}), .y({c_l3_2[126:0], 1'b0}), .z({c_l3_3[126:0], 1'b0}), .s(s_l4_3), .c(c_l4_3));
    csa u_csa_l5_1(.x({c_l3_4[126:0], 1'b0}), .y({c_l3_5[126:0], 1'b0}), .z(s_l4_1), .s(s_l5_1), .c(c_l5_1));
    csa u_csa_l5_2(.x(s_l4_2), .y(s_l4_3), .z({c_l4_1[126:0], 1'b0}), .s(s_l5_2), .c(c_l5_2));
    csa u_csa_l6_1(.x({c_l4_2[126:0], 1'b0}), .y({c_l4_3[126:0], 1'b0}), .z(s_l5_1), .s(s_l6_1), .c(c_l6_1));
    csa u_csa_l6_2(.x(s_l5_2), .y({c_l5_1[126:0], 1'b0}), .z({c_l5_2[126:0], 1'b0}), .s(s_l6_2), .c(c_l6_2));
    csa u_csa_l7(.x(s_l6_1), .y(s_l6_2), .z({c_l6_1[126:0], 1'b0}), .s(s_l7), .c(c_l7));
    csa u_csa_l8(.x({c_l6_2[126:0], 1'b0}), .y(s_l7), .z({c_l7[126:0], 1'b0}), .s(s_l8), .c(c_l8));
    
    assign x = s_l8;
    assign y = {c_l8[126:0], 1'b0};

endmodule

